// --- START OF FILE PlaceSystemController.cs ---

using System.Collections.Generic;
using UnityEngine;

namespace PlaceSystem
{
    /// <summary>
    /// 放置系统的核心控制器。将其附加到场景中的一个管理器GameObject上。
    /// </summary>
    public class PlaceSystemController : MonoBehaviour
    {
        [Header("层级设置")]
        [Tooltip("可放置的表面所在的层（如地面、桌面）")]
        public LayerMask surfaceLayer;
        [Tooltip("已被放置的物体所在的层")]
        public LayerMask placedObjectLayer;

        [Header("预览材质")]
        public Material validPlacementMaterial;
        public Material invalidPlacementMaterial;

        [Header("控制设置")]
        [Tooltip("每秒旋转度数")]
        public float rotationSpeed = 180f;

        [Header("相机设置")]
        public Camera mainCamera;

        private PlaceableObject _currentDraggingObject;

        // --- 拖拽状态变量 ---
        private Vector3 _startPosition;
        private Quaternion _startRotation;
        private Transform _startParent; // 用于存储物体原始的父节点
        private RaycastHit _lastSurfaceHit; // 用于存储最后一次命中的表面信息

        // 用于处理物体自身旋转的变量
        private float _currentYRotation;

        // 用于解决边缘拖拽问题的变量
        private Vector3 _mouseWorldPosition; // 鼠标在拖拽平面上的世界坐标
        private bool _isObjectOnSurface; // 标记物体当前是否在可放置表面上

        // --- 静态字典 ---
        private static readonly Dictionary<Collider, PlaceableObject> _collidersToPlaceableObjects = new();
        private static readonly Dictionary<Collider, PlacementSurface> _collidersToPlacementSurfaces = new();

        private void Update()
        {
            if (_currentDraggingObject == null)
            {
                if (Input.GetMouseButtonDown(0)) TryPickObject();
            }
            else
            {
                HandleDragging();
                if (Input.GetMouseButtonUp(0)) TryPlaceOrCancel();
            }
        }

        private void TryPickObject()
        {
            Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit, 1000f, placedObjectLayer))
            {
                if (_collidersToPlaceableObjects.TryGetValue(hit.collider, out PlaceableObject placeableObject))
                {
                    StartPlacing(placeableObject);
                }
            }
        }

        private void StartPlacing(PlaceableObject placeableObject)
        {
            _currentDraggingObject = placeableObject;
            Transform dragTransform = placeableObject.transform;

            _startPosition = dragTransform.position;
            _startRotation = dragTransform.rotation;

            // 记录初始的Y轴旋转角度
            _currentYRotation = dragTransform.eulerAngles.y;

            // 记录原始父节点，并解除父子关系
            _startParent = dragTransform.parent;
            dragTransform.SetParent(null, true); // true表示保持世界坐标不变

            // 禁用碰撞体以防自检测
            _currentDraggingObject.BeginDrag();
        }

        private void HandleDragging()
        {
            // --- 1. 处理旋转输入 ---
            HandleRotationInput();

            // --- 2. 计算鼠标在世界中的目标位置 ---
            Ray mouseRay = mainCamera.ScreenPointToRay(Input.mousePosition);

            Debug.DrawLine(mouseRay.origin, mouseRay.direction * 1000, Color.red);

            // --- 3. 更新物体位置与姿态 ---
            if (Physics.Raycast(mouseRay, out RaycastHit hit, 1000f, surfaceLayer))
            {
                // 检查击中的物体是否是已注册的可放置表面
                if (_collidersToPlacementSurfaces.ContainsKey(hit.collider))
                {
                    // 如果是，则吸附到表面
                    _isObjectOnSurface = true;
                    _lastSurfaceHit = hit; // 存储命中的表面信息
                    ApplySurfacePlacement(hit);
                }
                else
                {
                    _isObjectOnSurface = false;
                    ApplyFloatingPlacement(mouseRay);
                }
            }
            else
            {
                // 如果下方没有表面，则保持在空中
                _isObjectOnSurface = false;
                ApplyFloatingPlacement(mouseRay);
            }

            // --- 4. 检测空间是否被占用，并更新预览材质 ---
            CheckPlacementValidity();
        }

        /// <summary>
        /// 当物体在可放置表面上时的定位与旋转逻辑
        /// </summary>
        private void ApplySurfacePlacement(RaycastHit hit)
        {
            Transform current = _currentDraggingObject.transform;

            // 将物体定位到表面接触点
            current.position = hit.point;

            // 组合旋转：先应用自身Y轴旋转，再贴合表面法线
            Quaternion yRotation = Quaternion.Euler(0, _currentYRotation, 0);
            Quaternion surfaceAlignment = Quaternion.FromToRotation(Vector3.up, hit.normal);
            current.rotation = surfaceAlignment * yRotation;

            // 设置预览材质
            _currentDraggingObject.SetPreviewMaterial(validPlacementMaterial);
        }

        /// <summary>
        /// 当物体悬浮在空中时的定位与旋转逻辑
        /// </summary>
        private void ApplyFloatingPlacement(Ray mouseRay)
        {
            // 计算鼠标射线与一个与相机平行的、经过物体当前位置的平面的交点
            Plane dragPlane = new Plane(-mainCamera.transform.forward, _currentDraggingObject.transform.position);
            if (dragPlane.Raycast(mouseRay, out float distance))
            {
                _mouseWorldPosition = mouseRay.GetPoint(distance);
                _currentDraggingObject.transform.position = _mouseWorldPosition;
            }

            // 旋转恢复到初始姿态 + 当前的Y轴旋转
            _currentDraggingObject.transform.rotation = Quaternion.Euler(0, _currentYRotation, 0);
        }

        /// <summary>
        /// 检测当前位置是否有空间放置物体，并据此更新预览材质
        /// </summary>
        private bool CheckPlacementValidity()
        {
            // 如果不在可放置表面上，则视为无效，并恢复原始材质
            if (!_isObjectOnSurface)
            {
                _currentDraggingObject.RestoreOriginalMaterials();
                return false;
            }

            bool hasSpace = !_currentDraggingObject.CheckBox(placedObjectLayer);

            if (hasSpace)
            {
                _currentDraggingObject.SetPreviewMaterial(validPlacementMaterial);
                return true;
            }
            else
            {
                _currentDraggingObject.SetPreviewMaterial(invalidPlacementMaterial);
                return false;
            }
        }

        /// <summary>
        /// 尝试放置或取消放置
        /// </summary>
        private void TryPlaceOrCancel()
        {
            // 检查最终位置是否有效
            var canPlace = CheckPlacementValidity();

            if (canPlace && _isObjectOnSurface) // 必须在表面上且空间有效才能放置
            {
                PlaceComplete();
            }
            else
            {
                PlaceCancel();
            }
        }

        private void PlaceComplete()
        {
            // 将物体设置为命中表面的子节点
            if (_collidersToPlacementSurfaces.TryGetValue(_lastSurfaceHit.collider, out var placementSurface))
            {
                _currentDraggingObject.transform.SetParent(placementSurface.transform, true);
            }
            _currentDraggingObject.EndDrag();
            _currentDraggingObject.RestoreOriginalMaterials();
            _currentDraggingObject = null;
        }

        private void PlaceCancel()
        {
            var tran = _currentDraggingObject.transform;
            tran.position = _startPosition;
            tran.rotation = _startRotation;

            // 恢复物体的原始父节点
            tran.SetParent(_startParent, true);

            _currentDraggingObject.EndDrag();
            _currentDraggingObject.RestoreOriginalMaterials();
            _currentDraggingObject = null;
        }

        /// <summary>
        /// 处理Q/E旋转输入
        /// </summary>
        private void HandleRotationInput()
        {
            float rotationInput = 0;
            if (Input.GetKey(KeyCode.E)) rotationInput = 1;
            if (Input.GetKey(KeyCode.Q)) rotationInput = -1;

            if (rotationInput != 0)
            {
                // 只累加Y轴旋转角度
                _currentYRotation += rotationInput * rotationSpeed * Time.deltaTime;
            }
        }

        // --- 静态注册/注销方法 ---
        public static void EnablePlaceableObject(PlaceableObject placeableObject)
        {
            placeableObject.Register(_collidersToPlaceableObjects);
        }

        public static void DisablePlaceableObject(PlaceableObject placeableObject)
        {
            placeableObject.Unregister(_collidersToPlaceableObjects);
        }

        public static void EnablePlacementSurface(PlacementSurface placementSurface)
        {
            placementSurface.Register(_collidersToPlacementSurfaces);
        }

        public static void DisablePlacementSurface(PlacementSurface placementSurface)
        {
            placementSurface.Unregister(_collidersToPlacementSurfaces);
        }
    }
}

// --- END OF FILE PlaceSystemController.cs ---